package com.mlethe.library.widget.roundimage;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ViewGroup;

import androidx.annotation.ColorInt;
import androidx.appcompat.widget.AppCompatImageView;

/**
 * 圆角图片
 *
 * @author Mlethe
 * created at  2019/11/18  17:33
 */
public class RoundImageView extends AppCompatImageView {
    private Paint paint, bitmapPaint, borderPaint;
    private float topLeftRadius = 0, topRightRadius = 0, bottomLeftRadius = 0, bottomRightRadius = 0;
    private int paddingLeft, paddingRight, paddingTop, paddingBottom;
    private float width, height;
    private float widthSize, heightSize;
    private float borderWidth = 0;
    private int borderColor = Color.WHITE;
    /**
     * 布局宽高尺寸比
     */
    private float ratio = 0f;

    public RoundImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
    }

    public RoundImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public RoundImageView(Context context) {
        super(context);
        init(context, null);
    }

    private void init(Context context, AttributeSet attrs) {

        float radius = 0;
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
            widthSize = a.getLayoutDimension(R.styleable.RoundImageView_android_layout_width,  0);
            heightSize = a.getLayoutDimension(R.styleable.RoundImageView_android_layout_height,  0);
            radius = a.getDimensionPixelSize(R.styleable.RoundImageView_radius, 0);
            topLeftRadius = a.getDimensionPixelSize(R.styleable.RoundImageView_topLeftRadius, (int) topLeftRadius);
            topRightRadius = a.getDimensionPixelSize(R.styleable.RoundImageView_topRightRadius, (int) topRightRadius);
            bottomLeftRadius = a.getDimensionPixelSize(R.styleable.RoundImageView_bottomLeftRadius, (int) bottomLeftRadius);
            bottomRightRadius = a.getDimensionPixelSize(R.styleable.RoundImageView_bottomRightRadius, (int) bottomRightRadius);
            borderWidth = a.getDimensionPixelSize(R.styleable.RoundImageView_borderWidth, (int) borderWidth);
            borderColor = a.getColor(R.styleable.RoundImageView_borderColor, borderColor);
            String layoutRatio = a.getString(R.styleable.RoundImageView_layoutRatio);
            // （宽：高 => 4:1）
            if (!TextUtils.isEmpty(layoutRatio)) {
                String[] strings = layoutRatio.split(":");
                if (strings.length >= 2) {
                    ratio = Float.parseFloat(strings[0]) / Float.parseFloat(strings[1]);
                }
            }
            a.recycle();
        } else {
            float density = context.getResources().getDisplayMetrics().density;
            radius = radius * density;
            topLeftRadius = topLeftRadius * density;
            topRightRadius = topRightRadius * density;
            bottomLeftRadius = bottomLeftRadius * density;
            bottomRightRadius = bottomRightRadius * density;
        }

        if (radius > 0) {
            topLeftRadius = radius;
            topRightRadius = radius;
            bottomLeftRadius = radius;
            bottomRightRadius = radius;
        }

        paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setAntiAlias(true);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));

        bitmapPaint = new Paint();
        bitmapPaint.setXfermode(null);

        borderPaint = new Paint();
        borderPaint.setColor(borderColor);
        borderPaint.setAntiAlias(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 获取宽度的模式和尺寸
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthSize == ViewGroup.LayoutParams.MATCH_PARENT) {
            widthSize = MeasureSpec.getSize(widthMeasureSpec);
        }
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightSize == ViewGroup.LayoutParams.MATCH_PARENT) {
            heightSize = MeasureSpec.getSize(heightMeasureSpec);
        }
        if (widthSize == ViewGroup.LayoutParams.WRAP_CONTENT && heightSize == ViewGroup.LayoutParams.WRAP_CONTENT) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            return;
        }
        if (ratio > 0) {
            // 根据宽高比ratio和模式创建一个测量值
            if (widthSize == 0 || widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED) {
                widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (heightSize * ratio), MeasureSpec.EXACTLY);
            } else if (heightSize == 0 || heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
                heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (widthSize / ratio), MeasureSpec.EXACTLY);
            }
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        paddingLeft = getPaddingLeft();
        paddingRight = getPaddingRight();
        paddingTop = getPaddingTop();
        paddingBottom = getPaddingBottom();
        width = w - paddingLeft - paddingRight;
        height = h - paddingTop - paddingBottom;
    }

    @Override
    public void draw(Canvas canvas) {
        int width = getWidth();
        int height = getHeight();
        if (width > 0 && height > 0) {
            Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
            Canvas canvas2 = new Canvas(bitmap);
            super.draw(canvas2);
            if (topLeftRadius > 0) {
                drawLiftUp(canvas2);
            }
            if (topRightRadius > 0) {
                drawRightUp(canvas2);
            }
            if (bottomLeftRadius > 0) {
                drawLiftDown(canvas2);
            }
            if (bottomRightRadius > 0) {
                drawRightDown(canvas2);
            }
            drawTop(canvas2);
            drawRight(canvas2);
            drawBottom(canvas2);
            drawLeft(canvas2);
            if (borderWidth > 0) {
                // 绘制圆环
                borderPaint.setStrokeWidth(borderWidth);
                borderPaint.setStyle(Paint.Style.STROKE);
                drawLeftUpBorder(canvas2);
                drawRightUpBorder(canvas2);
                drawRightDownBorder(canvas2);
                drawLeftDownBorder(canvas2);
                borderPaint.setStrokeWidth(0);
                borderPaint.setStyle(Paint.Style.FILL);
                drawTopBorder(canvas2);
                drawRightBorder(canvas2);
                drawBottomBorder(canvas2);
                drawLeftBorder(canvas2);
            }
            canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);
            bitmap.recycle();
        } else {
            super.draw(canvas);
        }
    }

    private void drawTopBorder(Canvas canvas) {
        canvas.drawRect(paddingLeft + topLeftRadius, paddingTop - borderWidth, width - topRightRadius + paddingLeft, paddingTop, borderPaint);
    }

    private void drawRightBorder(Canvas canvas) {
        canvas.drawRect(width + paddingLeft, topRightRadius + paddingTop, width + paddingLeft + borderWidth, height - bottomRightRadius + paddingTop, borderPaint);
    }

    private void drawBottomBorder(Canvas canvas) {
        canvas.drawRect(bottomLeftRadius + paddingLeft, height + paddingTop, width - bottomRightRadius + paddingLeft, height + paddingTop + borderWidth, borderPaint);
    }

    private void drawLeftBorder(Canvas canvas) {
        canvas.drawRect(paddingLeft - borderWidth, topLeftRadius + paddingTop, paddingLeft, height - bottomLeftRadius + paddingTop, borderPaint);
    }

    private void drawLeftUpBorder(Canvas canvas) {
        RectF oval = new RectF(
                paddingLeft - borderWidth / 2,
                paddingTop - borderWidth / 2,
                topLeftRadius * 2 + paddingLeft + borderWidth / 2,
                topLeftRadius * 2 + paddingTop + borderWidth / 2);
        canvas.drawArc(oval, -90, -90, false, borderPaint);
    }

    private void drawRightUpBorder(Canvas canvas) {
        RectF oval = new RectF(
                width - topRightRadius * 2 + paddingLeft - borderWidth / 2,
                paddingTop - borderWidth / 2,
                width + paddingLeft + borderWidth / 2,
                topRightRadius * 2 + paddingTop + borderWidth / 2);
        canvas.drawArc(oval, -90, 90, false, borderPaint);
    }

    private void drawRightDownBorder(Canvas canvas) {
        RectF oval = new RectF(
                width - bottomRightRadius * 2 + paddingLeft - borderWidth / 2,
                height - bottomRightRadius * 2 + paddingTop - borderWidth / 2,
                width + paddingLeft + borderWidth / 2,
                height + paddingTop + borderWidth / 2);
        canvas.drawArc(oval, 0, 90, false, borderPaint);
    }

    private void drawLeftDownBorder(Canvas canvas) {
        RectF oval = new RectF(
                paddingLeft - borderWidth / 2,
                height - bottomLeftRadius * 2 + paddingTop - borderWidth / 2,
                bottomLeftRadius * 2 + paddingLeft + borderWidth / 2,
                height + paddingTop + borderWidth / 2);
        canvas.drawArc(oval, 90, 90, false, borderPaint);
    }

    private void drawTop(Canvas canvas) {
        canvas.drawRect(topLeftRadius + paddingLeft, 0, width - topRightRadius + paddingLeft, paddingTop, paint);
    }

    private void drawRight(Canvas canvas) {
        canvas.drawRect(width + paddingLeft, topRightRadius + paddingTop, width + paddingLeft + paddingRight, height - bottomRightRadius + paddingTop, paint);
    }

    private void drawBottom(Canvas canvas) {
        canvas.drawRect(topLeftRadius + paddingLeft, height + paddingTop, width - bottomRightRadius + paddingLeft, height + paddingTop + paddingBottom, paint);
    }

    private void drawLeft(Canvas canvas) {
        canvas.drawRect(0, topLeftRadius + paddingTop, paddingLeft, height - bottomLeftRadius + paddingTop, paint);
    }

    private void drawLiftUp(Canvas canvas) {
        Path path = new Path();
        path.moveTo(paddingLeft, topLeftRadius + paddingTop);
        path.lineTo(0, topLeftRadius + paddingTop);
        path.lineTo(0, 0);
        path.lineTo(topLeftRadius + paddingLeft, 0);
        path.lineTo(topLeftRadius + paddingLeft, paddingTop);
        path.arcTo(new RectF(
                        paddingLeft,
                        paddingTop,
                        topLeftRadius * 2 + paddingLeft,
                        topLeftRadius * 2 + paddingTop),
                -90,
                -90);
        path.close();
        canvas.drawPath(path, paint);
    }

    private void drawRightUp(Canvas canvas) {
        Path path = new Path();
        path.moveTo(width + paddingLeft, topRightRadius + paddingTop);
        path.lineTo(width + paddingLeft + paddingRight, topRightRadius + paddingTop);
        path.lineTo(width + paddingLeft + paddingRight, 0);
        path.lineTo(width - topRightRadius + paddingLeft, 0);
        path.lineTo(width - topRightRadius + paddingLeft, paddingTop);
        path.arcTo(new RectF(
                        width - topRightRadius * 2 + paddingLeft,
                        paddingTop,
                        width + paddingLeft,
                        topRightRadius * 2 + paddingTop),
                -90,
                90);
        path.close();
        canvas.drawPath(path, paint);
    }

    private void drawLiftDown(Canvas canvas) {
        Path path = new Path();
        path.moveTo(paddingLeft, height - bottomLeftRadius + paddingTop);
        path.lineTo(0, height - bottomLeftRadius + paddingTop);
        path.lineTo(0, height + paddingTop + paddingBottom);
        path.lineTo(bottomLeftRadius + paddingLeft, height + paddingTop + paddingBottom);
        path.lineTo(bottomLeftRadius + paddingLeft, height + paddingTop);
        path.arcTo(new RectF(
                        paddingLeft,
                        height - bottomLeftRadius * 2 + paddingTop,
                        bottomLeftRadius * 2 + paddingLeft,
                        height + paddingTop),
                90,
                90);
        path.close();
        canvas.drawPath(path, paint);
    }

    private void drawRightDown(Canvas canvas) {
        Path path = new Path();
        path.moveTo(width - bottomRightRadius + paddingLeft, height + paddingTop);
        path.lineTo(width - bottomRightRadius + paddingLeft, height + paddingTop + paddingBottom);
        path.lineTo(width + paddingLeft + paddingRight, height + paddingTop + paddingBottom);
        path.lineTo(width + paddingLeft + paddingRight, height - bottomRightRadius + paddingTop);
        path.lineTo(width + paddingLeft, height - bottomRightRadius + paddingTop);
        path.arcTo(new RectF(
                width - bottomRightRadius * 2 + paddingLeft,
                height - bottomRightRadius * 2 + paddingTop,
                width + paddingLeft,
                height + paddingTop), 0, 90);
        path.close();
        canvas.drawPath(path, paint);
    }

    /**
     * 设置圆角（单位dp）
     *
     * @param radius dp
     */
    public RoundImageView setRadius(float radius) {
        float radiusPx = dp2px(radius);
        topLeftRadius = radiusPx;
        topRightRadius = radiusPx;
        bottomLeftRadius = radiusPx;
        bottomRightRadius = radiusPx;
        invalidate();
        return this;
    }

    /**
     * 设置圆角（单位dp）
     *
     * @param topLeft     dp
     * @param topRight    dp
     * @param bottomRight dp
     * @param bottomLeft  dp
     */
    public RoundImageView setRadius(float topLeft, float topRight, float bottomRight, float bottomLeft) {
        topLeftRadius = dp2px(topLeft);
        topRightRadius = dp2px(topRight);
        bottomLeftRadius = dp2px(bottomRight);
        bottomRightRadius = dp2px(bottomLeft);
        invalidate();
        return this;
    }

    /**
     * 设置边框宽度（单位dp）
     *
     * @param width dp
     */
    public RoundImageView setBorderWidth(float width) {
        width = dp2px(width);
        if (this.borderWidth == width) {
            return this;
        }
        this.borderWidth = width;
        invalidate();
        return this;
    }

    /**
     * 设置边框颜色
     *
     * @param color
     */
    public RoundImageView setBorderColor(@ColorInt int color) {
        if (this.borderColor == color) {
            return this;
        }
        this.borderColor = color;
        invalidate();
        return this;
    }

    /**
     * dp转px
     *
     * @param dp
     * @return
     */
    private float dp2px(float dp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }
}
